home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / www / library / implemen / htformat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  17.0 KB  |  682 lines

  1.  
  2. /*        Manage different file formats            HTFormat.c
  3. **        =============================
  4. **
  5. ** Bugs:
  6. **    Not reentrant.
  7. **
  8. **    Assumes the incoming stream is ASCII, rather than a local file
  9. **    format, and so ALWAYS converts from ASCII on non-ASCII machines.
  10. **    Therefore, non-ASCII machines can't read local files.
  11. **
  12. */
  13.  
  14.  
  15. /* Implements:
  16. */
  17. #include"capalloc.h"
  18. #include"capstdio.h"
  19. #include "HTFormat.h"
  20.  
  21. PUBLIC float HTMaxSecs = 1e10;        /* No effective limit */
  22. PUBLIC float HTMaxLength = 1e10;    /* No effective limit */
  23.  
  24. #ifdef unix
  25. #ifdef NeXT
  26. #define PRESENT_POSTSCRIPT "open %s; /bin/rm -f %s\n"
  27. #else
  28. #define PRESENT_POSTSCRIPT "(ghostview %s ; /bin/rm -f %s)&\n"
  29.     /* Full pathname would be better! */
  30. #endif
  31. #endif
  32.  
  33.  
  34. #include "HTUtils.h"
  35. #include "tcp.h"
  36.  
  37. #include "HTML.h"
  38. #include "HTMLDTD.h"
  39. #include "HText.h"
  40. #include "HTAlert.h"
  41. #include "HTList.h"
  42. #include "HTInit.h"
  43. /*    Streams and structured streams which we use:
  44. */
  45. #include "HTFWriter.h"
  46. #include "HTPlain.h"
  47. #include "SGML.h"
  48. #include "HTML.h"
  49. #include "HTMLGen.h"
  50. #include"HTFile.h"
  51.  
  52. PUBLIC    BOOL HTOutputSource = NO;    /* Flag: shortcut parser to stdout */
  53. extern  BOOL interactive;
  54.  
  55. #ifdef ORIGINAL
  56. struct _HTStream {
  57.       CONST HTStreamClass*    isa;
  58.       /* ... */
  59. };
  60. #endif
  61.  
  62. /* this version used by the NetToText stream */
  63. struct _HTStream {
  64.     CONST HTStreamClass *        isa;
  65.     BOOL            had_cr;
  66.     HTStream *         sink;
  67. };
  68.  
  69.  
  70. /*    Presentation methods
  71. **    --------------------
  72. */
  73.  
  74. PUBLIC  HTList * HTPresentations = 0;
  75. PUBLIC  HTPresentation* default_presentation = 0;
  76.  
  77.  
  78. /*    Define a presentation system command for a content-type
  79. **    -------------------------------------------------------
  80. */
  81. PUBLIC void HTSetPresentation ARGS5(
  82.     CONST char *, representation,
  83.     CONST char *, command,
  84.     float,    quality,
  85.     float,    secs, 
  86.     float,    secs_per_byte
  87. ){
  88.  
  89.     HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
  90.     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
  91.  
  92.     pres->rep = HTAtom_for(representation);
  93.     pres->rep_out = WWW_PRESENT;        /* Fixed for now ... :-) */
  94.     pres->converter = HTSaveAndExecute;        /* Fixed for now ...     */
  95.     pres->quality = quality;
  96.     pres->secs = secs;
  97.     pres->secs_per_byte = secs_per_byte;
  98.     pres->rep = HTAtom_for(representation);
  99.     pres->command = 0;
  100.     StrAllocCopy(pres->command, command);
  101.     
  102.     if (!HTPresentations) HTPresentations = HTList_new();
  103.     
  104.     if (strcmp(representation, "*")==0) {
  105.         if (default_presentation) free(default_presentation);
  106.     default_presentation = pres;
  107.     } else {
  108.         HTList_addObject(HTPresentations, pres);
  109.     }
  110. }
  111.  
  112.  
  113. /*    Define a built-in function for a content-type
  114. **    ---------------------------------------------
  115. */
  116. PUBLIC void HTSetConversion ARGS6(
  117.     CONST char *, representation_in,
  118.     CONST char *, representation_out,
  119.     HTConverter*,    converter,
  120.     float,    quality,
  121.     float,    secs, 
  122.     float,    secs_per_byte
  123. ){
  124.  
  125.     HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
  126.     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
  127.     
  128.     pres->rep = HTAtom_for(representation_in);
  129.     pres->rep_out = HTAtom_for(representation_out);
  130.     pres->converter = converter;
  131.     pres->command = NULL;        /* Fixed */
  132.     pres->quality = quality;
  133.     pres->secs = secs;
  134.     pres->secs_per_byte = secs_per_byte;
  135.     pres->command = 0;
  136.  
  137.     if (!HTPresentations) HTPresentations = HTList_new();
  138.     
  139.     if (strcmp(representation_in, "*")==0) {
  140.         if (default_presentation) free(default_presentation);
  141.     default_presentation = pres;
  142.     } else {
  143.         HTList_addObject(HTPresentations, pres);
  144.     }
  145. }
  146.  
  147.  
  148.  
  149. /*    File buffering
  150. **    --------------
  151. **
  152. **    The input file is read using the macro which can read from
  153. **    a socket or a file.
  154. **    The input buffer size, if large will give greater efficiency and
  155. **    release the server faster, and if small will save space on PCs etc.
  156. */
  157. #define INPUT_BUFFER_SIZE 4096        /* Tradeoff */
  158. PRIVATE char input_buffer[INPUT_BUFFER_SIZE];
  159. PRIVATE char * input_pointer;
  160. PRIVATE char * input_limit;
  161. PRIVATE int input_file_number;
  162.  
  163.  
  164. /*    Set up the buffering
  165. **
  166. **    These routines are public because they are in fact needed by
  167. **    many parsers, and on PCs and Macs we should not duplicate
  168. **    the static buffer area.
  169. */
  170. PUBLIC void HTInitInput ARGS1 (int,file_number)
  171. {
  172.     input_file_number = file_number;
  173.     input_pointer = input_limit = input_buffer;
  174. }
  175.  
  176.  
  177. PUBLIC char HTGetChararcter NOARGS
  178. {
  179.     char ch;
  180.  
  181.     do {
  182.     if (input_pointer >= input_limit) {
  183.         int status = NETREAD(
  184.             input_file_number, input_buffer, INPUT_BUFFER_SIZE);
  185.         if (status <= 0) {
  186.         if (status == 0) return (char)EOF;
  187. #ifndef RELEASE
  188.         if (TRACE) fprintf(stderr,
  189.             "HTFormat: File read error %d\n", status);
  190. #endif /* RELEASE */
  191.         return (char)EOF; /* -1 is returned by UCX at end of HTTP link */
  192.         }
  193.         input_pointer = input_buffer;
  194.         input_limit = input_buffer + status;
  195.     }
  196.     ch = *input_pointer++;
  197.     } while (ch == (char) 13); /* Ignore ASCII carriage return */
  198.  
  199.     return FROMASCII(ch);
  200. }
  201.  
  202. /*    Stream the data to an ouput file as binary
  203. */
  204. PUBLIC int HTOutputBinary ARGS2( int,         input,
  205.                   FILE *,     output)
  206. {
  207.     do {
  208.         int status = NETREAD(
  209.             input, input_buffer, INPUT_BUFFER_SIZE);
  210.         if (status <= 0) {
  211.         if (status == 0) return 0;
  212. #ifndef RELEASE
  213.         if (TRACE) fprintf(stderr,
  214.             "HTFormat: File read error %d\n", status);
  215. #endif /* RELEASE */
  216.         return 2;            /* Error */
  217.         }
  218.         fwrite(input_buffer, sizeof(char), status, output);
  219.     } while (YES);
  220. }
  221.  
  222.  
  223. /*        Create a filter stack
  224. **        ---------------------
  225. **
  226. **    If a wildcard match is made, a temporary HTPresentation
  227. **    structure is made to hold the destination format while the
  228. **    new stack is generated. This is just to pass the out format to
  229. **    MIME so far.  Storing the format of a stream in the stream might
  230. **    be a lot neater.
  231. **
  232. **    The www/source format is special, in that if you can take
  233. **    that you can take anything. However, we
  234. */
  235. PUBLIC HTStream * HTStreamStack ARGS4(
  236.     HTFormat,        rep_in,
  237.     HTFormat,        rep_out,
  238.     HTStream*,        sink,
  239.     HTParentAnchor*,    anchor)
  240. {
  241.     HTAtom * wildcard = HTAtom_for("*");
  242.     HTFormat source = WWW_SOURCE;
  243. #ifndef RELEASE
  244.     if (TRACE) fprintf(stderr,
  245.     "HTFormat: Constructing stream stack for %s to %s\n",
  246.     HTAtom_name(rep_in),
  247.     HTAtom_name(rep_out));
  248. #endif /* RELEASE */
  249.  
  250.     if (rep_out == WWW_SOURCE ||
  251.     rep_out == rep_in) return sink;
  252.  
  253.     if (!HTPresentations) HTFormatInit();    /* set up the list */
  254.  
  255.     {
  256.     int n = HTList_count(HTPresentations);
  257.     int i;
  258.     HTPresentation * pres, *match, *wildcard_match=0,
  259.             *source_match=0, *source_wildcard_match=0;
  260.     for(i=0; i<n; i++) {
  261.         pres = HTList_objectAt(HTPresentations, i);
  262.         if (pres->rep == rep_in) {
  263.         if (pres->rep_out == rep_out)
  264.             return (*pres->converter)(pres, anchor, sink);
  265.         if (pres->rep_out == wildcard) {
  266.             wildcard_match = pres;
  267.         }
  268.         }
  269.         if (pres->rep == source) {
  270.         if (pres->rep_out == rep_out)
  271.             source_match = pres;
  272.         if (pres->rep_out == wildcard) {
  273.             source_wildcard_match = pres;
  274.         }
  275.         }
  276.     }
  277.  
  278.     match = wildcard_match ? wildcard_match :
  279.         source_match ?    source_match :
  280.         source_wildcard_match;
  281.  
  282.     if (match) {
  283.         HTPresentation temp;
  284.         temp = *match;            /* Specific instance */
  285.         temp.rep = rep_in;        /* yuk */
  286.         temp.rep_out = rep_out;        /* yuk */
  287.         return (*match->converter)(&temp, anchor, sink);
  288.     }
  289.     }
  290.  
  291.  
  292. #ifdef XMOSAIC_HACK_REMOVED_NOW  /* Use above source method instead */
  293.     return sink;
  294. #else
  295.     return NULL;
  296. #endif
  297. }
  298.  
  299.  
  300. /*        Find the cost of a filter stack
  301. **        -------------------------------
  302. **
  303. **    Must return the cost of the same stack which StreamStack would set up.
  304. **
  305. ** On entry,
  306. **    length    The size of the data to be converted
  307. */
  308. PUBLIC float HTStackValue ARGS4(
  309.     HTFormat,        rep_in,
  310.     HTFormat,        rep_out,
  311.     float,            initial_value,
  312.     long int,        length)
  313. {
  314.     HTAtom * wildcard = HTAtom_for("*");
  315.  
  316. #ifndef RELEASE
  317.     if (TRACE) fprintf(stderr,
  318.     "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
  319.     HTAtom_name(rep_in),    initial_value,
  320.     HTAtom_name(rep_out));
  321. #endif /* RELEASE */
  322.  
  323.     if (rep_out == WWW_SOURCE ||
  324.     rep_out == rep_in) return 0.0;
  325.  
  326.     if (!HTPresentations) HTFormatInit();    /* set up the list */
  327.  
  328.     {
  329.     int n = HTList_count(HTPresentations);
  330.     int i;
  331.     HTPresentation * pres;
  332.     for(i=0; i<n; i++) {
  333.         pres = HTList_objectAt(HTPresentations, i);
  334.         if (pres->rep == rep_in && (
  335.             pres->rep_out == rep_out ||
  336.             pres->rep_out == wildcard)) {
  337.         float value = initial_value * pres->quality;
  338.         if (HTMaxSecs != 0.0)
  339.         value = value - (length*pres->secs_per_byte + pres->secs)
  340.                      /HTMaxSecs;
  341.         return value;
  342.         }
  343.     }
  344.     }
  345.  
  346.     return -1e30;        /* Really bad */
  347.  
  348. }
  349.  
  350.  
  351. /*    Push data from a socket down a stream
  352. **    -------------------------------------
  353. **
  354. **   This routine is responsible for creating and PRESENTING any
  355. **   graphic (or other) objects described by the file.
  356. **
  357. **   The file number given is assumed to be a TELNET stream ie containing
  358. **   CRLF at the end of lines which need to be stripped to LF for unix
  359. **   when the format is textual.
  360. **
  361. */
  362. PUBLIC void HTCopy ARGS2(
  363.     int,            file_number,
  364.     HTStream*,        sink)
  365. {
  366.     HTStreamClass targetClass;
  367.  
  368. /*    Push the data down the stream
  369. **
  370. */
  371.     targetClass = *(sink->isa);    /* Copy pointers to procedures */
  372.  
  373.     /*    Push binary from socket down sink
  374.     **
  375.     **        This operation could be put into a main event loop
  376.     */
  377.     for(;;) {
  378.     int status = NETREAD(
  379.         file_number, input_buffer, INPUT_BUFFER_SIZE);
  380.     if (status <= 0) {
  381.         if (status == 0) break;
  382. #ifndef RELEASE
  383.         if (TRACE) fprintf(stderr,
  384.         "HTFormat: Read error, read returns %d\n", status);
  385. #endif /* RELEASE */
  386.         break;
  387.     }
  388.  
  389. #ifdef NOT_ASCII
  390.     {
  391.         char * p;
  392.         for(p = input_buffer; p < input_buffer+status; p++) {
  393.         *p = FROMASCII(*p);
  394.         }
  395.     }
  396. #endif
  397.  
  398.     (*targetClass.put_block)(sink, input_buffer, status);
  399.     } /* next bufferload */
  400.  
  401. }
  402.  
  403.  
  404.  
  405. /*    Push data from a file pointer down a stream
  406. **    -------------------------------------
  407. **
  408. **   This routine is responsible for creating and PRESENTING any
  409. **   graphic (or other) objects described by the file.
  410. **
  411. **
  412. */
  413. PUBLIC void HTFileCopy ARGS2(
  414.     FILE *,            fp,
  415.     HTStream*,        sink)
  416. {
  417.     HTStreamClass targetClass;
  418.  
  419. /*    Push the data down the stream
  420. **
  421. */
  422.     targetClass = *(sink->isa);    /* Copy pointers to procedures */
  423.  
  424.     /*    Push binary from socket down sink
  425.     */
  426.     for(;;) {
  427.     int status = fread(
  428.            input_buffer, 1, INPUT_BUFFER_SIZE, fp);
  429.     if (status == 0) { /* EOF or error */
  430.         if (ferror(fp) == 0) break;
  431. #ifndef RELEASE
  432.         if (TRACE) fprintf(stderr,
  433.         "HTFormat: Read error, read returns %d\n", ferror(fp));
  434. #endif /* RELEASE */
  435.         break;
  436.     }
  437.     (*targetClass.put_block)(sink, input_buffer, status);
  438.     } /* next bufferload */
  439.  
  440. }
  441.  
  442.  
  443.  
  444.  
  445. /*    Push data from a socket down a stream STRIPPING CR
  446. **    --------------------------------------------------
  447. **
  448. **   This routine is responsible for creating and PRESENTING any
  449. **   graphic (or other) objects described by the socket.
  450. **
  451. **   The file number given is assumed to be a TELNET stream ie containing
  452. **   CRLF at the end of lines which need to be stripped to LF for unix
  453. **   when the format is textual.
  454. **
  455. */
  456. PUBLIC void HTCopyNoCR ARGS2(
  457.     int,            file_number,
  458.     HTStream*,        sink)
  459. {
  460.     HTStreamClass targetClass;
  461.  
  462. /*    Push the data, ignoring CRLF, down the stream
  463. **
  464. */
  465.     targetClass = *(sink->isa);    /* Copy pointers to procedures */
  466.  
  467. /*    Push text from telnet socket down sink
  468. **
  469. **    @@@@@ To push strings could be faster? (especially is we
  470. **    cheat and don't ignore CR! :-}
  471. */
  472.     HTInitInput(file_number);
  473.     for(;;) {
  474.     char character;
  475.     character = HTGetChararcter();
  476.     if (character == (char)EOF) break;
  477.     (*targetClass.put_character)(sink, character);
  478.     }
  479. }
  480.  
  481.  
  482.  
  483. /*    Parse a socket given format and file number
  484. **
  485. **   This routine is responsible for creating and PRESENTING any
  486. **   graphic (or other) objects described by the file.
  487. **
  488. **   The file number given is assumed to be a TELNET stream ie containing
  489. **   CRLF at the end of lines which need to be stripped to LF for unix
  490. **   when the format is textual.
  491. **
  492. */
  493. PUBLIC int HTParseSocket ARGS5(
  494.     HTFormat,        rep_in,
  495.     HTFormat,        format_out,
  496.     HTParentAnchor *,    anchor,
  497.     int,            file_number,
  498.     HTStream*,        sink)
  499. {
  500.     HTStream * stream;
  501.     HTStreamClass targetClass;
  502.     auto HTAtom *HTAp_encoding;
  503.  
  504.     stream = HTStreamStack(rep_in,
  505.             format_out,
  506.             sink , anchor);
  507.  
  508.     if (!stream) {
  509.     char buffer[1024];    /* @@@@@@@@ */
  510.     sprintf(buffer, "Sorry, can't convert from %s to %s.",
  511.         HTAtom_name(rep_in), HTAtom_name(format_out));
  512. #ifndef RELEASE
  513.     if (TRACE) fprintf(stderr, "HTFormat: %s\n", buffer);
  514. #endif /* RELEASE */
  515.     return HTLoadError(sink, 501, buffer);
  516.     }
  517.  
  518. /*    Push the data, ignoring CRLF if necessary, down the stream
  519. **
  520. **
  521. **   @@  Bug:  This decision ought to be made based on "encoding"
  522. **   rather than on format.  @@@  When we handle encoding.
  523. **   The current method smells anyway.
  524. */
  525.     targetClass = *(stream->isa);    /* Copy pointers to procedures */
  526.  
  527.     /*
  528.      *    Figure out the encoding, or try.
  529.      */
  530.     {
  531.         auto char *cp_fakefile = NULL;
  532.  
  533.         StrAllocCopy(cp_fakefile, "fakefile");
  534.         StrAllocCat(cp_fakefile, HTFileSuffix(rep_in));
  535.  
  536.         HTFileFormat(cp_fakefile, &HTAp_encoding);
  537.         free(cp_fakefile);
  538.     }
  539.  
  540. /*
  541.     if(rep_in == WWW_BINARY || HTOutputSource
  542.     || strstr(HTAtom_name(rep_in), "image/")
  543.     || strstr(HTAtom_name(rep_in), "video/")) {
  544. */
  545.  
  546.     if(HTAp_encoding == HTAtom_for("binary"))    {
  547.         HTCopy(file_number, stream);
  548.     }
  549.     else    {   /* ascii text with CRLFs :-( */
  550.         HTCopyNoCR(file_number, stream);
  551.     }
  552.     (*targetClass.free)(stream);
  553.  
  554.     return(HT_LOADED);
  555. }
  556.  
  557.  
  558.  
  559. /*    Parse a file given format and file pointer
  560. **
  561. **   This routine is responsible for creating and PRESENTING any
  562. **   graphic (or other) objects described by the file.
  563. **
  564. **   The file number given is assumed to be a TELNET stream ie containing
  565. **   CRLF at the end of lines which need to be stripped to \n for unix
  566. **   when the format is textual.
  567. **
  568. */
  569. PUBLIC int HTParseFile ARGS5(
  570.     HTFormat,        rep_in,
  571.     HTFormat,        format_out,
  572.     HTParentAnchor *,    anchor,
  573.     FILE *,            fp,
  574.     HTStream*,        sink)
  575. {
  576.     HTStream * stream;
  577.     HTStreamClass targetClass;
  578.  
  579.     stream = HTStreamStack(rep_in,
  580.             format_out,
  581.             sink , anchor);
  582.  
  583.     if (!stream) {
  584.     char buffer[1024];    /* @@@@@@@@ */
  585.     sprintf(buffer, "Sorry, can't convert from %s to %s.",
  586.         HTAtom_name(rep_in), HTAtom_name(format_out));
  587. #ifndef RELEASE
  588.     if (TRACE) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
  589. #endif /* RELEASE */
  590.     return HTLoadError(sink, 501, buffer);
  591.     }
  592.  
  593. /*    Push the data down the stream
  594. **
  595. **
  596. **   @@  Bug:  This decision ought to be made based on "encoding"
  597. **   rather than on content-type.  @@@  When we handle encoding.
  598. **   The current method smells anyway.
  599. */
  600.     targetClass = *(stream->isa);    /* Copy pointers to procedures */
  601.     HTFileCopy(fp, stream);
  602.     (*targetClass.free)(stream);
  603.  
  604.     return HT_LOADED;
  605. }
  606.  
  607.  
  608. /*    Converter stream: Network Telnet to internal character text
  609. **    -----------------------------------------------------------
  610. **
  611. **    The input is assumed to be in ASCII, with lines delimited
  612. **    by (13,10) pairs, These pairs are converted into (CR,LF)
  613. **    pairs in the local representation.  The (CR,LF) sequence
  614. **    when found is changed to a '\n' character, the internal
  615. **    C representation of a new line.
  616. */
  617.  
  618.  
  619. PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char)
  620. {
  621.     char c = FROMASCII(net_char);
  622.     if (me->had_cr) {
  623.     if (c==LF) {
  624.         me->sink->isa->put_character(me->sink, '\n');    /* Newline */
  625.         me->had_cr = NO;
  626.         return;
  627.     } else {
  628.         me->sink->isa->put_character(me->sink, CR);    /* leftover */
  629.     }
  630.     }
  631.     me->had_cr = (c==CR);
  632.     if (!me->had_cr)
  633.     me->sink->isa->put_character(me->sink, c);        /* normal */
  634. }
  635.  
  636. PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s)
  637. {
  638.     CONST char * p;
  639.     for(p=s; *p; p++) NetToText_put_character(me, *p);
  640. }
  641.  
  642. PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l)
  643. {
  644.     CONST char * p;
  645.     for(p=s; p<(s+l); p++) NetToText_put_character(me, *p);
  646. }
  647.  
  648. PRIVATE void NetToText_free ARGS1(HTStream *, me)
  649. {
  650.     me->sink->isa->free(me->sink);        /* Close rest of pipe */
  651.     free(me);
  652. }
  653.  
  654. PRIVATE void NetToText_abort ARGS2(HTStream *, me, HTError, e)
  655. {
  656.     me->sink->isa->abort(me->sink,e);        /* Abort rest of pipe */
  657.     free(me);
  658. }
  659.  
  660. /*    The class structure
  661. */
  662. PRIVATE HTStreamClass NetToTextClass = {
  663.     "NetToText",
  664.     NetToText_free,
  665.     NetToText_abort,
  666.     NetToText_put_character,
  667.     NetToText_put_string,
  668.     NetToText_put_block
  669. };
  670.  
  671. /*    The creation method
  672. */
  673. PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink)
  674. {
  675.     HTStream* me = (HTStream*)malloc(sizeof(*me));
  676.     if (me == NULL) outofmem(__FILE__, "NetToText");
  677.     me->isa = &NetToTextClass;
  678.  
  679.     me->had_cr = NO;
  680.     me->sink = sink;
  681.     return me;
  682. }